﻿using System.Collections;
using System.Text;
using OnDash.Mathematics.Vector;
using OnDash.Windowing.GraphicsLibraryFramework.Enums;

namespace OnDash.Windowing.GraphicsLibraryFramework.Inputs;

public class MouseState
{
    internal const int MaxButtons = 16;

    private readonly BitArray _buttons = new(MaxButtons);
    private readonly BitArray _buttonsPrevious = new(MaxButtons);

    public MouseState()
    {
    }

    private MouseState(MouseState source)
    {
        Position = source.Position;
        PreviousPosition = source.PreviousPosition;

        Scroll = source.Scroll;
        PreviousScroll = source.PreviousScroll;

        _buttons = (BitArray)source._buttons.Clone();
        _buttonsPrevious = (BitArray)source._buttonsPrevious.Clone();
    }

    public Vector2 Position { get; internal set; }

    public Vector2 PreviousPosition { get; internal set; }

    public Vector2 Delta =>
        Position - PreviousPosition;

    public Vector2 Scroll { get; internal set; }
    public Vector2 PreviousScroll { get; internal set; }

    public Vector2 ScrollDelta =>
        Scroll - PreviousScroll;

    public bool this[MouseButton button]
    {
        get => _buttons[(int)button];
        internal set => _buttons[(int)button] = value;
    }

    public float X =>
        Position.X;

    public float Y =>
        Position.Y;

    public float PreviousX =>
        PreviousPosition.X;

    public float PreviousY =>
        PreviousPosition.Y;


    public bool IsAnyButtonDown
    {
        get
        {
            for (var i = 0; i < MaxButtons; i++)
                if (_buttons[i])
                    return true;

            return false;
        }
    }

    public override string ToString()
    {
        var b = new StringBuilder();
        for (var i = 0; i < MaxButtons; i++)
            b.Append(_buttons[i] ? "1" : "0");

        return $"[X={X}, Y={Y}, Buttons={b}]";
    }

    internal void Update()
    {
        _buttonsPrevious.SetAll(false);
        _buttonsPrevious.Or(_buttons);

        PreviousPosition = Position;
        PreviousScroll = Scroll;
    }

    public bool IsButtonDown(MouseButton button) =>
        _buttons[(int)button];

    public bool WasButtonDown(MouseButton button) =>
        _buttonsPrevious[(int)button];

    public bool IsButtonPressed(MouseButton button) =>
        _buttons[(int)button] && !_buttonsPrevious[(int)button];

    public bool IsButtonReleased(MouseButton button) =>
        !_buttons[(int)button] && _buttonsPrevious[(int)button];

    public MouseState GetSnapshot() =>
        new(this);
}